﻿using System;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace WCYCReader.Utility.SocketHelper
{
    /// <summary>
    /// 封装 Socket对象，负责与 PC 服务器端进行通信的自定义类
    /// </summary>
    public class SocketClient
    {
        // 控制异步套接字的方法所使用的缓冲区的最大尺寸
        const int Max_Buffer_Size = 1024 * 4;

        // 当操作完成后，触发消息通知
        public event EventHandler<string> Completed;

        // 负责与 PC端通信
        Socket socket;

        /// <summary>
        ///  建立与 PC 端通信的连接
        /// </summary>
        /// <param name="hostName">远程服务器的 IP地址</param>
        /// <param name="portNumber">端口号</param>
        public void Connect(string hostName, int portNumber)
        {
            //this.SocketShutDowm();

            // 将网络终结点表示为主机名或 IP 地址和端口号的字符串表示形式。
            DnsEndPoint dnsEndPoint = new DnsEndPoint(hostName, portNumber);

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // 表示异步套接字操作。
            SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();

            // 远程 IP 或 DNS 终结点
            socketAsyncEventArgs.RemoteEndPoint = dnsEndPoint;

            socketAsyncEventArgs.Completed += socketAsyncEventArgs_Completed;

            socketAsyncEventArgs.UserToken = null;

            // 开始一个对远程主机连接的异步请求。
            socket.ConnectAsync(socketAsyncEventArgs);
        }

        /// <summary>
        /// 监听服务器端发来的数据
        /// </summary>
        /// <returns></returns>
        public Task Receive()
        {
            return Task.Factory.StartNew(() =>
                 {
                     if (socket != null)
                     {
                         // 表示异步套接字操作。
                         SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();

                         socketAsyncEventArgs.Completed += socketAsyncEventArgs_Completed;

                         socketAsyncEventArgs.RemoteEndPoint = socket.RemoteEndPoint;

                         socketAsyncEventArgs.UserToken = null;

                         socketAsyncEventArgs.SetBuffer(new byte[Max_Buffer_Size], 0, Max_Buffer_Size);

                         // 开始一个异步请求以便从连接的 Socket 对象中接收数据。
                         bool result = socket.ReceiveAsync(socketAsyncEventArgs);
                     }
                     else
                     {
                         OnCompleted("还没有建立连接");
                     }
                 });
        }

        /// <summary>
        /// 向服务器端发送文件
        /// </summary>
        /// <param name="dataType">body 的数据类型</param>
        /// <param name="byteFile">文件的 byte[]内容</param>
        /// <returns></returns>
        public Task SendFile(DataType dataType, byte[] byteFile)
        {
            return Task.Factory.StartNew(() =>
            {
                if (socket != null)
                {
                    SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();

                    socketAsyncEventArgs.Completed += socketAsyncEventArgs_Completed;

                    socketAsyncEventArgs.RemoteEndPoint = socket.RemoteEndPoint;

                    socketAsyncEventArgs.UserToken = null;

                    byte[] sendBytes = CommonHelper.ConvertFileToByte(dataType, byteFile);

                    //  设置要用于异步套接字方法的数据缓冲区。
                    socketAsyncEventArgs.SetBuffer(sendBytes, 0, sendBytes.Length);

                    // 将数据异步发送到连接的 Socket 对象
                    bool result = socket.SendAsync(socketAsyncEventArgs);
                }
                else
                {
                    OnCompleted("还没有建立连接");
                }
            });
        }

        /// <summary>
        /// 向服务器端发送 文件 或者 文字 内容
        /// </summary>
        /// <param name="dataType">文件类型</param>
        /// <param name="strPath">文件路径</param>
        /// <param name="strMsg">文字消息</param>
        /// <returns></returns>
        public Task Send(DataType dataType, string strPath, string strMsg)
        {
            return Task.Factory.StartNew(() =>
            {
                if (socket != null)
                {
                    SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();

                    socketAsyncEventArgs.Completed += socketAsyncEventArgs_Completed;

                    socketAsyncEventArgs.RemoteEndPoint = socket.RemoteEndPoint;

                    socketAsyncEventArgs.UserToken = null;

                    byte[] sendBytes = CommonHelper.ConvertDataToByte(dataType, strPath, strMsg);

                    socketAsyncEventArgs.SetBuffer(sendBytes, 0, sendBytes.Length);

                    // 将数据异步发送到连接的 Socket 对象
                    bool result = socket.SendAsync(socketAsyncEventArgs);
                }
                else
                {
                    OnCompleted("还没有建立连接");
                }
            });
        }

        // 异步操作完成时调用
        void socketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            //  获取最近使用此对象执行的异步套接字操作的类型。
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Connect:
                    ProcessConnect(e);
                    break;
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    break;
                case SocketAsyncOperation.ReceiveFrom:
                    ProcessReceiveFrom(e);
                    break;
                case SocketAsyncOperation.Send:
                    ProcessSend(e);
                    break;
                case SocketAsyncOperation.SendTo:
                    ProcessSendTo(e);
                    break;
                default:
                    throw new Exception("未知操作");
            }
        }

        // 处理 socket连接 操作的回调
        void ProcessConnect(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                OnCompleted("连接服务器成功");
                //Socket socket = e.UserToken as Socket;

                Receive();
            }
            else
            {
                OnCompleted("连接服务器失败 ：" + e.SocketError.ToString());
            }
        }

        // 处理服务器端发送来的数据
        async void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                string strMsg = null;
                byte[] byteFile = null;
                DataType dataType = null;
                CommonHelper.ConvertByteToData(e.Buffer, out dataType, out  byteFile, out strMsg);

                if (dataType != null && dataType.IsFile == true)
                {
                    await CommonHelper.SaveFile(dataType.FileName + dataType.Exten, byteFile);

                    OnCompleted("已经保存服务器发送的文件：" + dataType.FileName + dataType.Exten);
                }
                else
                {
                    OnCompleted(">>服务器：" + strMsg);
                }

                // 处理完服务器发送的数据后，继续等待消息
                Receive();
            }
            else
            {
                OnCompleted(e.SocketError.ToString());
            }
        }

        void ProcessReceiveFrom(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {

            }
            else
            {
                OnCompleted(e.SocketError.ToString());
            }
        }

        // 处理向服务器端发送数据后的回调
        void ProcessSend(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                string str = Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length);

            }
            else
            {
                OnCompleted(e.SocketError.ToString());
            }
        }

        void ProcessSendTo(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {


            }
            else
            {
                OnCompleted(e.SocketError.ToString());
            }
        }

        // 关闭 Socket 
        public void SocketShutDowm()
        {
            if (socket != null)
            {
                socket.Close();
                socket.Dispose();
            }
        }

        // 向宿主页面显示消息
        void OnCompleted(string strMsg)
        {
            if (Completed != null)
            {
                Completed(null, strMsg);
            }
        }
    }
}
